﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Slock.Utility;
using Microsoft.Xna.Framework.Graphics;

namespace Slock.Components
{
    /// <summary>
    /// Holds basic settings for the world
    /// </summary>
    public class WorldInfo
    {
        /// <summary>
        /// Cube vertices
        /// </summary>
        public static readonly VertexPositionNormalTexture[] CubeVertices;
        /// <summary>
        /// Cube indices
        /// </summary>
        public static readonly short[] Indices;

        /// <summary>
        /// Direction and force of gravitational pull in the world
        /// </summary>
        public static Vector3 Gravity = new Vector3(0, 0, -12);

        /// <summary>
        /// Size of a terrain patch in blocks
        /// </summary>
        public static readonly Point3 Terrain_Patch_Dimension = new Point3() { X = 8, Y = 8, Z = 8 };

        /// <summary>
        /// Initial world size for level generation (is in patches)
        /// </summary>
        public static readonly Point3 Initial_World_Dimensions = new Point3(4, 4, 2);

        /// <summary>
        /// The center of the world
        /// </summary>
        public static readonly Vector3 Origin = Vector3.Zero;

        /// <summary>
        /// The axis defining the upward direction in the world
        /// </summary>
        public static readonly Vector3 Up = new Vector3(0, 0, 1);

        /// <summary>
        /// The axis defining the downward direction in the world
        /// </summary>
        public static readonly Vector3 Down = new Vector3(0, 0, -1);

        /// <summary>
        /// The axis defining the forward direction
        /// </summary>
        public static readonly Vector3 Forward = new Vector3(1, 0, 0);

        /// <summary>
        /// The axis defining the backward direction
        /// </summary>
        public static readonly Vector3 Backward = new Vector3(-1, 0, 0);

        /// <summary>
        /// The axis defining the Right direction
        /// </summary>
        public static readonly Vector3 Right = new Vector3(0, 1, 0);

        /// <summary>
        /// The axis defining the Left direction
        /// </summary>
        public static readonly Vector3 Left = new Vector3(0, -1, 0);

        /// <summary>
        /// Number of Actors that can exist in a voxel before they are distributed
        /// </summary>
        public static int Meshes_Per_Voxel = 1;

        /// <summary>
        /// The smallest dimension that a voxel can be
        /// </summary>
        public static float Minimum_Voxel_Size = Terrain_Patch_Dimension.X * BLOCK_SIZE;

        /// <summary>
        /// The field of view angle for cameras
        /// </summary>
        public const float FIELD_OF_VIEW = MathHelper.PiOver4;

        /// <summary>
        /// The far clipping distance for cameras
        /// </summary>
        public const float FAR_CLIP = 512.0f;

        /// <summary>
        /// The near clipping plane distance for cameras
        /// </summary>
        public const float NEAR_CLIP = 0.01f;

        /// <summary>
        /// Maximum number of players the engine will be able to support per world
        /// </summary>
        public const int MAX_PLAYERS = 16;

        /// <summary>
        /// The maximum number of local players
        /// </summary>
        public const int MAX_LOCAL_PLAYERS = 1;

        /// <summary>
        /// The size of each block
        /// </summary>
        public const int BLOCK_SIZE = 5;

        /// <summary>
        /// How long a player must wait after dying to respawn
        /// </summary>
        public const float PLAYER_SPAWN_TIME = 2.3f;

        /// <summary>
        /// If the octree bounding boxes should be drawn
        /// </summary>
        public static bool DrawOctreeExtents = true;

        /// <summary>
        /// The color of fog in the world
        /// </summary>
        public static Color FogColor = Color.SlateGray;

        #region Initialization

        static WorldInfo()
        {
            CubeVertices = new VertexPositionNormalTexture[24];

            Vector3 topLeftFront =
                new Vector3(-1.0f, 1.0f, -1.0f) * BLOCK_SIZE / 2;
            Vector3 bottomLeftFront =
                new Vector3(-1.0f, -1.0f, -1.0f) * BLOCK_SIZE / 2;
            Vector3 topRightFront =
                new Vector3(1.0f, 1.0f, -1.0f) * BLOCK_SIZE / 2;
            Vector3 bottomRightFront =
                new Vector3(1.0f, -1.0f, -1.0f) * BLOCK_SIZE / 2;
            Vector3 topLeftBack =
                new Vector3(-1.0f, 1.0f, 1.0f) * BLOCK_SIZE / 2;
            Vector3 topRightBack =
                new Vector3(1.0f, 1.0f, 1.0f) * BLOCK_SIZE / 2;
            Vector3 bottomLeftBack =
                new Vector3(-1.0f, -1.0f, 1.0f) * BLOCK_SIZE / 2;
            Vector3 bottomRightBack =
                new Vector3(1.0f, -1.0f, 1.0f) * BLOCK_SIZE / 2;

            Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f);
            Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);
            Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f);
            Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f);

            Vector2 textureTopLeft = new Vector2(0, 0.0f);
            Vector2 textureTopRight = new Vector2(1, 0);
            Vector2 textureBottomLeft = new Vector2(0, 1);
            Vector2 textureBottomRight = new Vector2(1, 1);
            //         _________________________
            //        /4_____________________ 5/|
            //       / / ___________________/ / |
            //      / / /| |               / /  |
            //     / / / | |              / / . |
            //    / / /| | |             / / /| |
            //   / / / | | |            / / / | |
            //  / / /  | | |           / / /| | |
            // / /_/__________________/ / / | | |
            ///________________________/ /  | | |
            //|0______________________1| |  | | |
            //| | |    | | |_________| | |__| | |
            //| | |    | |___________| | |____| |
            //| | |   / /6___________| | |_ 7/ /
            //| | |  / / /           | | |/ / /
            //| | | / / /            | | | / /
            //| | |/ / /             | | |/ /
            //| | | / /              | | ' /
            //| | |/_/_______________| |  /
            //| |____________________| | /
            //|2______________________3|/
            // Front face.
            CubeVertices[0] = new VertexPositionNormalTexture(
                topLeftFront, frontNormal, textureTopLeft);
            CubeVertices[1] = new VertexPositionNormalTexture(
                bottomLeftFront, frontNormal, textureBottomLeft);
            CubeVertices[2] = new VertexPositionNormalTexture(
                topRightFront, frontNormal, textureTopRight);
            CubeVertices[3] = new VertexPositionNormalTexture(
                bottomRightFront, frontNormal, textureBottomRight);

            // Back face.
            CubeVertices[4] = new VertexPositionNormalTexture(
                topLeftBack, backNormal, textureTopLeft);
            CubeVertices[5] = new VertexPositionNormalTexture(
                bottomLeftBack, backNormal, textureBottomLeft);
            CubeVertices[6] = new VertexPositionNormalTexture(
                topRightBack, backNormal, textureTopRight);
            CubeVertices[7] = new VertexPositionNormalTexture(
                bottomRightBack, backNormal, textureBottomRight);

            // Top face.
            CubeVertices[8] = new VertexPositionNormalTexture(
                topLeftBack, topNormal, textureTopLeft);
            CubeVertices[9] = new VertexPositionNormalTexture(
                topLeftFront, topNormal, textureBottomLeft);
            CubeVertices[10] = new VertexPositionNormalTexture(
                topRightBack, topNormal, textureTopRight);
            CubeVertices[11] = new VertexPositionNormalTexture(
                topRightFront, topNormal, textureBottomRight);

            // Bottom face. 
            CubeVertices[12] = new VertexPositionNormalTexture(
                bottomLeftBack, bottomNormal, textureTopLeft);
            CubeVertices[13] = new VertexPositionNormalTexture(
                bottomLeftFront, bottomNormal, textureBottomLeft);
            CubeVertices[14] = new VertexPositionNormalTexture(
                bottomRightBack, bottomNormal, textureTopRight);
            CubeVertices[15] = new VertexPositionNormalTexture(
                bottomRightFront, bottomNormal, textureBottomRight);

            // Left face.
            CubeVertices[16] = new VertexPositionNormalTexture(
                topLeftBack, leftNormal, textureTopLeft);
            CubeVertices[17] = new VertexPositionNormalTexture(
                bottomLeftBack, leftNormal, textureBottomLeft);
            CubeVertices[18] = new VertexPositionNormalTexture(
                topLeftFront, leftNormal, textureTopRight);
            CubeVertices[19] = new VertexPositionNormalTexture(
                bottomLeftFront, leftNormal, textureBottomRight);

            // Right face. 
            CubeVertices[20] = new VertexPositionNormalTexture(
                topRightBack, rightNormal, textureTopLeft);
            CubeVertices[21] = new VertexPositionNormalTexture(
                bottomRightBack, rightNormal, textureBottomLeft);
            CubeVertices[22] = new VertexPositionNormalTexture(
                topRightFront, rightNormal, textureTopRight);
            CubeVertices[23] = new VertexPositionNormalTexture(
                bottomRightFront, rightNormal, textureBottomRight);

            Indices = new short[36];

            // Front
            Indices[0] = 0;
            Indices[1] = 1;
            Indices[2] = 2;
            Indices[3] = 1;
            Indices[4] = 3;
            Indices[5] = 2;

            // Back
            Indices[6] = 4;
            Indices[7] = 6;
            Indices[8] = 5;
            Indices[9] = 5;
            Indices[10] = 6;
            Indices[11] = 7;

            // Top
            Indices[12] = 8;
            Indices[13] = 9;
            Indices[14] = 10;
            Indices[15] = 9;
            Indices[16] = 11;
            Indices[17] = 10;

            // Bottom
            Indices[18] = 13;
            Indices[19] = 12;
            Indices[20] = 14;
            Indices[21] = 13;
            Indices[22] = 14;
            Indices[23] = 15;

            // Left
            Indices[24] = 18;
            Indices[25] = 17;
            Indices[26] = 19;
            Indices[27] = 16;
            Indices[28] = 17;
            Indices[29] = 18;

            // Right
            Indices[30] = 22;
            Indices[31] = 23;
            Indices[32] = 21;
            Indices[33] = 20;
            Indices[34] = 22;
            Indices[35] = 21;
        }

        #endregion

    }
}
